#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <signal.h> 
#include <stdlib.h>       
#include <string.h>
#include <pthread.h>
//#include <sys/sem.h>
#include <errno.h>
#include <sys/ipc.h>
//#include <sys/msg.h>
#include <sys/timeb.h>
#include <sys/socket.h>
//#include <sys/socketvar.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <semaphore.h>
#include <string.h>
#include <termios.h>
#include <linux/input.h>
#include <semaphore.h>
#include <linux/shm.h>
#include <asm/unistd.h>
#include <sys/poll.h>

#include "../common.h"


#define logBufSize 512

#define MAX_BYTES_IN_LINE 1024

#define CARD_TIME_BYTES 6
#define MAX_PAGE_NUMBER 20
#define MAX_CARD_NUMBER_EACH_PAGE 50

static const int getOnePageCardDataMaxWaitTime = 3;
static const int getOneCardDataMaxWaitTime = 2;

static const unsigned int delayBeforeFisrtTimeToGetAllData = 1 * 60;	//consider about route start time
static const unsigned int persistenceTimeInteral_S = 10 * 60;
//static const unsigned int persistenceTimeInteral_S = 10;
static const unsigned int retryDelayTimeWhenGetAllDataFail_S = 10 * 60;

static const char defaultPersistenceFileDir[] = "/data/edu/accessCard.config";

//protoSlaveType
enum _protoSlaveType
{
	_getAllAccessCardInfoReply = 0x00,
	_getOneAccessCardInfoReply = 0x01,
};

typedef enum 
{
	eNotLoop = 0,
	eDayLoop,
	eWeekLoop,
	eMonthLoop,
	eMaxLoop,
}LoopType;

typedef struct
{
	unsigned char cardIdBytes;
	char cardId[MAX_CARD_NUMBER_BYTES];
	unsigned char startTime[CARD_TIME_BYTES];
	unsigned char stopTime[CARD_TIME_BYTES];
	LoopType loop;
}RealCardInfoType;

typedef struct 
{
	unsigned char useCards;
	RealCardInfoType realCardInfo[MAX_CARD_NUMBER_EACH_PAGE];
}PageCardInfoType;

typedef struct
{
	pthread_rwlock_t lock;
	sem_t sem;
	unsigned char totalPageNum;
	unsigned char bytesOfEachCard;
	PageCardInfoType realCardInfos[MAX_PAGE_NUMBER];
	//int dataIsRight;
}CardInfosType;

typedef struct 
{
	pthread_mutex_t lock;
	sem_t sem;
	RealCardInfoType realCardInfo;
	int returnRet;
}OneCardProtoInfoType;

static TypeC256 defaultAccessCardServerDomainName = "www.incastyun.cn:7890";

extern SystemParam *pgSystemParam;

static CardInfosType *pCardInfos = NULL;
static OneCardProtoInfoType *pOneCardProtoInfo = NULL;


static void getAllAccessCardInfoReply(struct recvData *recvData, struct packageFilter *pFilter);
static void getOneAccessCardInfoReply(struct recvData *recvData, struct packageFilter *pFilter);

static int getAllAccessCardInfo();
static int getOnePageAccessCardInfo(const unsigned char pageNumber);

static int getOneAccessCardInfoFromCache(const char *pCardId,  const unsigned char cardIdBytes);

static int checkTimeEqual(const struct tm *tA, const struct tm *tB, LoopType loop = eNotLoop);
static int checkTimeEqualNotLoop(const struct tm *tA, const struct tm *tB);
static int checkTimeEqualDayLoop(const struct tm *tA, const struct tm *tB);
static int checkTimeEqualMonthLoop(const struct tm *tA, const struct tm *tB);
static int checkTimeEqualWeekLoop(const struct tm *tA, const struct tm *tB);

static int checkTimeOk(const unsigned char *pStart, const unsigned char *pStop, const LoopType loop);
static struct tm changeDateInfoFromArrayToStruct(const unsigned char *pTime);

static int strcmpEx(const char *strA, const char *strB, const unsigned char size);

static void changeTimeFormat(unsigned char *pOut, const char *pIn);
static void reverseChangeTimeFormat(char *pOut, const unsigned char *pIn);
static unsigned char getWday(int year, int month, int mday);

static void* dataPersistenceThread(void *arg);

static void printAllCacheData();

int initNetACServer()
{
	int ret;
	pCardInfos = (CardInfosType*)malloc(sizeof(CardInfosType));
	if(!pCardInfos)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "pCardInfos malloc fail ! ret = %d\n", ret);
		LOGD(logBuf);
		return -1;
	}
	memset(pCardInfos, 0, sizeof(CardInfosType));
		
	ret = pthread_rwlock_init(&(pCardInfos->lock), NULL);
	if(ret < 0)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "pthread_mutex_init fail ! ret = %d\n", ret);
		LOGD(logBuf);
		free(pCardInfos);
		pCardInfos = NULL;
		return -2;
	}
		
	ret = sem_init(&(pCardInfos->sem), 1, 0);
	if(ret < 0)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "sem_init fail ! ret = %d\n", ret);
		LOGD(logBuf);
		pthread_rwlock_destroy(&(pCardInfos->lock));
		free(pCardInfos);
		pCardInfos = NULL;
		return -3;
	}
		
	pOneCardProtoInfo = (OneCardProtoInfoType*)malloc(sizeof(OneCardProtoInfoType));
	if(!pOneCardProtoInfo)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "pOneCardProtoInfo malloc fail ! ret = %d\n", ret);
		LOGD(logBuf);
		pthread_rwlock_destroy(&(pCardInfos->lock));
		free(pCardInfos);
		pCardInfos = NULL;
		return -4;
	}
	memset(pOneCardProtoInfo, 0, sizeof(OneCardProtoInfoType));
	pOneCardProtoInfo->returnRet = -1;
		
	ret = pthread_mutex_init(&(pOneCardProtoInfo->lock), NULL);
	if(ret < 0)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "pthread_mutex_init fail ! ret = %d\n", ret);
		LOGD(logBuf);
		pthread_rwlock_destroy(&(pCardInfos->lock));
		free(pCardInfos);
		pCardInfos = NULL;
		free(pOneCardProtoInfo);
		pOneCardProtoInfo = NULL;
		return -5;
	}
		
	ret = sem_init(&(pOneCardProtoInfo->sem), 1, 0);
	if(ret < 0)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "sem_init fail ! ret = %d\n", ret);
		LOGD(logBuf);
		pthread_rwlock_destroy(&(pCardInfos->lock));
		free(pCardInfos);
		pCardInfos = NULL;
		pthread_mutex_destroy(&(pOneCardProtoInfo->lock));
		free(pOneCardProtoInfo);
		pOneCardProtoInfo = NULL;
		return -6;
	}
		
	pthread_t ptID;
	if( pthread_create(&ptID, NULL, dataPersistenceThread, (void *)0) != 0 )
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "create thread failure\n");
		LOGD(logBuf);
		pthread_rwlock_destroy(&(pCardInfos->lock));
		free(pCardInfos);
		pCardInfos = NULL;
		pthread_mutex_destroy(&(pOneCardProtoInfo->lock));
		free(pOneCardProtoInfo);
		return -7;
	}	
		
	return 0;
}

void netACServer(struct recvData *recvData)
{
	printf("into netACServer\n");
	if (recvData == NULL)
	{
		printf("recvData == NULL ! {%s(%d)}\n", __FILE__, __LINE__);
		return;
	}

	if (!pCardInfos)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "pCardInfos == NULL !\n");
		LOGD(logBuf);
		return;
	}

	if (!pOneCardProtoInfo)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "pOneCardProtoInfo == NULL !\n");
		LOGD(logBuf);
		return;
	}

	struct packageFilter filter;
	int ret = explainPackageHead(recvData, &filter);
	if (ret < 0)
	{
		return;
	}

	switch (filter.protoSlaveType)
	{
	case _getAllAccessCardInfoReply:
		getAllAccessCardInfoReply(recvData, &filter);
		break;
	case _getOneAccessCardInfoReply:
		getOneAccessCardInfoReply(recvData, &filter);
		break;
	default:
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "filter.protoSlaveType not right ! filter.protoMasterType=%x, filter.protoSlaveType = %x\n", filter.protoMasterType, filter.protoSlaveType);
		LOGD(logBuf);
		break;
	}
}


static void getAllAccessCardInfoReply(struct recvData *recvData, struct packageFilter *pFilter)
{
	printf("into getAllAccessCardInfoReply\n");
	if(pFilter->dataDirection != 0x01)	
	{
		printf("proto %x,%x pFilter->dataDirection error ! pFilter->dataDirection = %d\n", pFilter->protoMasterType, pFilter->protoSlaveType, pFilter->dataDirection);
		return;
	}
		
	if(pFilter->dataLen < (4 + 1))
	{
		printf("proto %x,%x pFilter->dataLen error ! pFilter->dataLen = %d\n", pFilter->protoMasterType, pFilter->protoSlaveType, pFilter->dataLen);
		return;
	}
		
	unsigned char totalPageNum = pFilter->pData[4];
	unsigned char curPageNum = pFilter->pData[5];
	unsigned char curTotalCardNum = pFilter->pData[6];
	unsigned char bytesOfEachCard = pFilter->pData[7];
	if(totalPageNum == 0 || curPageNum >= MAX_PAGE_NUMBER || curTotalCardNum >= MAX_CARD_NUMBER_EACH_PAGE || bytesOfEachCard > MAX_CARD_NUMBER_BYTES)
	{
		char logBuf[logBufSize];
		snprintf(logBuf,logBufSize,"param error! totalPageNum=%u,curPageNum=%u,curTotalCardNum=%u,bytesOfEachCard=%u\n",totalPageNum,curPageNum,curTotalCardNum,bytesOfEachCard);
		LOGD(logBuf);
		return;
	}
		
	unsigned char *pRealNetData = &(pFilter->pData[8]);
	PageCardInfoType *pCardIs = &(pCardInfos->realCardInfos[curPageNum]);
	RealCardInfoType *pCards = pCardIs->realCardInfo;
		
	pthread_rwlock_wrlock(&(pCardInfos->lock));
	pCardInfos->totalPageNum = totalPageNum;
	pCardInfos->bytesOfEachCard = bytesOfEachCard;
	pCardIs->useCards = curTotalCardNum;
		
	unsigned char i;
	unsigned char oneCardDataBytes = bytesOfEachCard + CARD_TIME_BYTES * 2 + 1; 
	unsigned char *pOneNetCardData;
	RealCardInfoType *pOneCard;
	printf("getNetData,totalPageNumber=%u,curPageNumber=%u,curTotalCardNum=%u,bytesOfEachCard=%u\n", totalPageNum,curPageNum,curTotalCardNum,bytesOfEachCard);
	for(i = 0; i < curTotalCardNum; i ++)
	{
		pOneNetCardData = &pRealNetData[oneCardDataBytes * i];
		pOneCard = &pCards[i];
		memcpy(pOneCard->cardId, pOneNetCardData, bytesOfEachCard);
		memcpy(pOneCard->startTime, &(pOneNetCardData[bytesOfEachCard]), CARD_TIME_BYTES);
		memcpy(pOneCard->stopTime, &(pOneNetCardData[bytesOfEachCard + CARD_TIME_BYTES]), CARD_TIME_BYTES);
		pOneCard->loop = (LoopType)(pOneNetCardData[bytesOfEachCard + CARD_TIME_BYTES * 2]);
		pOneCard->cardId[bytesOfEachCard] = '\0';
		if(pOneCard->loop >= eMaxLoop)
		{
			char logBuf[logBufSize];
			snprintf(logBuf, logBufSize, "loop error! we change it into not loop! pOneCard->loop=%u, eMaxLoop=%u\n", pOneCard->loop, eMaxLoop);
			LOGD(logBuf);
			pOneCard->loop = eNotLoop;
		}
		printf("cardid=%s,loop=%u,useCards=%u ", pOneCard->cardId,(unsigned char)pOneCard->loop,pCardIs->useCards);
		printf("start=");
		for(unsigned char j = 0; j < CARD_TIME_BYTES; j ++)
		{
			printf("%u",pOneCard->startTime[j]);
		}
		printf(" stop=");
		for(unsigned char j = 0; j < CARD_TIME_BYTES; j ++)
		{
			printf("%u",pOneCard->stopTime[j]);
		}
		printf("\n");
	}
	pthread_rwlock_unlock(&(pCardInfos->lock));	
	sem_post(&(pCardInfos->sem));
}

static void getOneAccessCardInfoReply(struct recvData *recvData, struct packageFilter *pFilter)
{
	if (pFilter->dataDirection != 0x01)
	{
		printf("proto %x,%x pFilter->dataDirection error ! pFilter->dataDirection = %d\n", pFilter->protoMasterType, pFilter->protoSlaveType, pFilter->dataDirection);
		return;
	}

	if (pFilter->dataLen < (4 + 1 + 1 + 1 + CARD_TIME_BYTES + CARD_TIME_BYTES + 1))
	{
		printf("proto %x,%x pFilter->dataLen error ! pFilter->dataLen = %d\n", pFilter->protoMasterType, pFilter->protoSlaveType, pFilter->dataLen);
		return;
	}

	unsigned char returnRet = pFilter->pData[4];
	if (returnRet != 0)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "getOneAccessCardInfoReply fail ! returnRet=%u\n", returnRet);
		LOGD(logBuf);
		pthread_mutex_lock(&(pOneCardProtoInfo->lock));
		pOneCardProtoInfo->returnRet = -1;
		pthread_mutex_unlock(&(pOneCardProtoInfo->lock));
		sem_post(&(pOneCardProtoInfo->sem));
		return;
	}

	unsigned char *pRealData = &(pFilter->pData[5]);
	unsigned char cardBytes = pRealData[0];
	if (cardBytes > MAX_CARD_NUMBER_BYTES)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "cardBytes > MAX_CARD_NUMBER_BYTES! cardBytes=%u,MAX_CARD_NUMBER_BYTES=%u\n", cardBytes, MAX_CARD_NUMBER_BYTES);
		LOGD(logBuf);
		return;
	}

	RealCardInfoType *pOne = &(pOneCardProtoInfo->realCardInfo);
	pthread_mutex_lock(&(pOneCardProtoInfo->lock));
	pOne->cardIdBytes = cardBytes;
	memcpy(pOne->cardId, &pRealData[1], cardBytes);
	memcpy(pOne->startTime, &pRealData[1 + cardBytes], CARD_TIME_BYTES);
	memcpy(pOne->stopTime, &pRealData[1 + cardBytes + CARD_TIME_BYTES], CARD_TIME_BYTES);
	pOne->loop = (LoopType)pRealData[1 + cardBytes + CARD_TIME_BYTES + CARD_TIME_BYTES];
	pOneCardProtoInfo->returnRet = 0;
	pthread_mutex_unlock(&(pOneCardProtoInfo->lock));
	sem_post(&(pOneCardProtoInfo->sem));
}


static int getAllAccessCardInfo()
{
	int ret;
	if(!pCardInfos)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "getAllAccessCardInfo fail ! because pCardInfos == NULL !\n");
		LOGD(logBuf);
		return -1;
	}
	
	struct timespec ts;
	struct timeval  tv;	
	while(1)
	{
		gettimeofday(&tv, NULL);
		ts.tv_sec = tv.tv_sec;
		ts.tv_nsec = tv.tv_usec * 1000;
		if (sem_timedwait(&(pCardInfos->sem), &ts) != 0)
		{
			break;
		}
	}		
    
	getOnePageAccessCardInfo(0);
	gettimeofday(&tv, NULL); 
	ts.tv_sec  = tv.tv_sec + getOnePageCardDataMaxWaitTime;
	ts.tv_nsec = tv.tv_usec * 1000;		
	ret = sem_timedwait(&(pCardInfos->sem),&ts);
	if(ret != 0)
	{
    	char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "getAllAccessCardInfo fail ! pageNum = 0\n");
		//LOGD(logBuf);
		printf(logBuf);
		return -2;
	}
    
	unsigned char totalPageNum, i;
	pthread_rwlock_wrlock(&(pCardInfos->lock));
	totalPageNum = pCardInfos->totalPageNum;
	pthread_rwlock_unlock(&(pCardInfos->lock));
    
	for(i = 1; i < totalPageNum; i ++)
	{
		while (1)
		{
			gettimeofday(&tv, NULL);
			ts.tv_sec = tv.tv_sec;
			ts.tv_nsec = tv.tv_usec * 1000;
			if (sem_timedwait(&(pCardInfos->sem), &ts) != 0)
			{
				break;
			}
		}		
		    
		getOnePageAccessCardInfo(i);
		gettimeofday(&tv, NULL); 
		ts.tv_sec  = tv.tv_sec + getOnePageCardDataMaxWaitTime;
		ts.tv_nsec = tv.tv_usec * 1000;		
		ret = sem_timedwait(&(pCardInfos->sem),&ts);
		if(ret != 0)
		{
			char logBuf[logBufSize];
			snprintf(logBuf, logBufSize, "getAllAccessCardInfo complete ! totalPageNum = %u, nowPageNum=%u\n", totalPageNum, i);
			LOGD(logBuf);
			return 0;
		}
	}
		
	char logBuf[logBufSize];
	snprintf(logBuf, logBufSize, "getAllAccessCardInfo complete ! totalPageNum = %u\n", totalPageNum);
	LOGD(logBuf);
	return 0;
}

static void dataPersistence()
{
	printf("into dataPersistence\n");
	FILE *fpWrite = fopen(defaultPersistenceFileDir, "w+");
	if (!fpWrite)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "fopen w+ file fail !  %s\n", defaultPersistenceFileDir);
		LOGD(logBuf);
		return;
	}

	printf("open dataPersistence file success !\n");
	unsigned char i, j;
	unsigned char *a, *b, l;
	int writeBytes;
	char lineData[MAX_BYTES_IN_LINE];
	PageCardInfoType *pPageInfos = pCardInfos->realCardInfos;
	PageCardInfoType *pOnePageInfo;
	RealCardInfoType *pOnePageCardIds;
	RealCardInfoType *pOneCard;
	char ta[CARD_TIME_BYTES * 3], tb[CARD_TIME_BYTES * 3];

	pthread_rwlock_rdlock(&(pCardInfos->lock));

	printf("pCardInfos->totalPageNum = %u\n", pCardInfos->totalPageNum);
	writeBytes = snprintf(lineData, MAX_BYTES_IN_LINE, "%u,%u\r\n", pCardInfos->totalPageNum, pCardInfos->bytesOfEachCard);
	fwrite(lineData, writeBytes, 1, fpWrite);
	lineData[0] = '\r';
	lineData[1] = '\n';
	fwrite(lineData, 2, 1, fpWrite);

	for (i = 0; i < pCardInfos->totalPageNum; i++)
	{
		pOnePageInfo = &pPageInfos[i];
		pOnePageCardIds = pOnePageInfo->realCardInfo;
		printf("page:%u, useCards=%u\n", i, pOnePageInfo->useCards);
		for (j = 0; j < pOnePageInfo->useCards; j++)
		{
			pOneCard = &pOnePageCardIds[j];
			pOneCard->cardId[pCardInfos->bytesOfEachCard] = '\0';
			a = pOneCard->startTime;
			b = pOneCard->stopTime;
			l = (unsigned char)(pOneCard->loop);
			reverseChangeTimeFormat(ta, a);
			reverseChangeTimeFormat(tb, b);
			writeBytes = snprintf(lineData, MAX_BYTES_IN_LINE, "%s,%s,%s,%u\n", pOneCard->cardId, ta, tb, l);
			printf("pOneCard->cardId=%s\n", pOneCard->cardId);
			printf("ta=%s\n", ta);
			printf("tb=%s\n", tb);
			fwrite(lineData, writeBytes, 1, fpWrite);
		}
		lineData[0] = '\r';
		lineData[1] = '\n';
		fwrite(lineData, 2, 1, fpWrite);
	}
	fclose(fpWrite);

	pthread_rwlock_unlock(&(pCardInfos->lock));
}

static int loadPersistenceData()
{
	printf("into loadPersistenceData\n");
	if(access(defaultPersistenceFileDir, F_OK) != 0)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "loadPersistenceData fail because no file !  %s\n", defaultPersistenceFileDir);
		LOGD(logBuf);
		return -1;		
	}
	
	FILE *fpRead = fopen(defaultPersistenceFileDir, "rb");
	if(!fpRead)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "fopen rb file fail !  %s\n", defaultPersistenceFileDir);
		LOGD(logBuf);
		return -2;		
	}
	
	unsigned char i,j,k;
	unsigned char *a, *b, l;
	int ret;
	char lineData[MAX_BYTES_IN_LINE];
	char *returnPointer;
	unsigned char totalPageNum, bytesOfEachCard, useCards = 0;
	PageCardInfoType *pPageInfos = pCardInfos->realCardInfos;
	PageCardInfoType *pOnePageInfo;
	RealCardInfoType *pOnePageCardIds;
	RealCardInfoType *pOneCard;
		
	returnPointer = fgets(lineData, MAX_BYTES_IN_LINE - 1, fpRead);
	if(!returnPointer)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "get file first line data fail !\n");
		LOGD(logBuf);
		return -3;		
	}
	//printf("loadPersistenceData: analyse 1\n");
	lineData[MAX_BYTES_IN_LINE - 1] = '\0';
	printf("%u:%s\n", strlen(lineData), lineData);

	ret = sscanf(lineData, "%u,%u\n", &totalPageNum, &bytesOfEachCard);		
	//printf("loadPersistenceData: analyse 10\n");
	if(ret < 0)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "get file first line data fail !\n");
		LOGD(logBuf);
		return -4;		
	}
	//printf("loadPersistenceData: analyse 11\n");
	if(totalPageNum == 0 || totalPageNum > MAX_PAGE_NUMBER || bytesOfEachCard == 0 || bytesOfEachCard > MAX_CARD_NUMBER_BYTES)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "file first line data error ! totalPageNum=%u, MAX_PAGE_NUMBER=%u, bytesOfEachCard=%u, MAX_CARD_NUMBER_BYTES=%u\n", \
				totalPageNum,MAX_PAGE_NUMBER, bytesOfEachCard, MAX_CARD_NUMBER_BYTES);
		LOGD(logBuf);
		return -5;		
	}
	//printf("loadPersistenceData: analyse 2\n");
	returnPointer = fgets(lineData, MAX_BYTES_IN_LINE - 1, fpRead);
	if(!returnPointer)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "get file first line data fail !\n");
		LOGD(logBuf);
		return -6;		
	}
	//printf("loadPersistenceData: analyse 3\n");
	if(lineData[0] != '\r' || lineData[1] != '\n')
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "file first line data format error !\n");
		LOGD(logBuf);
		return -7;		
	}
		
	pthread_rwlock_wrlock(&(pCardInfos->lock));
	pCardInfos->totalPageNum = totalPageNum;
	pCardInfos->bytesOfEachCard = bytesOfEachCard;
	//printf("loadPersistenceData: analyse 4\n");
	char ta[CARD_TIME_BYTES * 3], tb[CARD_TIME_BYTES * 3];
	for(i = 0; i < totalPageNum; i ++)
	{
		pOnePageInfo = &pPageInfos[i];
		pOnePageCardIds = pOnePageInfo->realCardInfo;
		for(j = 0; j < MAX_CARD_NUMBER_EACH_PAGE; j ++)
		{
			returnPointer = fgets(lineData, MAX_BYTES_IN_LINE - 1, fpRead);
			if(!returnPointer)
			{
				char logBuf[logBufSize];
				snprintf(logBuf, logBufSize, "get new line data fail ! i=%u, j=%u\n", i,j);
				LOGD(logBuf);
				break;		
			}
					
			if(lineData[0] == '\r' && lineData[1] == '\n')
			{
				break;
			}

			printf("%u,%u,lineData:%s\n", i,j,lineData);
			//printf("loadPersistenceData: analyse 5\n");
			pOneCard = &pOnePageCardIds[j];
			a = pOneCard->startTime;
			b = pOneCard->stopTime;
			ret = sscanf(lineData, "%[^','],%[^','],%[^','],%[^'\r']", pOneCard->cardId, ta, tb, &l);			
			if(ret < 0)
			{
				char logBuf[logBufSize];
				snprintf(logBuf, logBufSize, "get file first line data fail !\n");
				LOGD(logBuf);
				return -9;		
			}	

			pOneCard->cardId[bytesOfEachCard] = '\0';
			ta[CARD_TIME_BYTES * 3 - 1] = '\0';
			tb[CARD_TIME_BYTES * 3 - 1] = '\0';
			printf("ta=%s, tb=%s\n", ta,tb);
			changeTimeFormat(a, ta);
			changeTimeFormat(b, tb);
			//printf("loadPersistenceData: analyse 6\n");
			pOneCard->loop = (LoopType)(l - '0');			
			useCards ++;				
						
			printf("%u,%u:", i,j);
			for(k = 0; k < bytesOfEachCard; k ++)
			{
				printf("%x ", pOneCard->cardId[k]);	
			}
			printf("\n");
			//printf("pOneCard->cardId[0] = %x\n", k,pOneCard->cardId[0]);
			//printf("pOneCard->cardId[1] = %x\n", k,pOneCard->cardId[1]);
			//printf("pOneCard->cardId[2] = %x\n", k,pOneCard->cardId[2]);
			//printf("pOneCard->cardId[3] = %x\n", k,pOneCard->cardId[3]);
			//printf("pOneCard->cardId[4] = %x\n", k,pOneCard->cardId[4]);
			//printf("pOneCard->cardId[5] = %x\n", k,pOneCard->cardId[5]);
			//printf("pOneCard->cardId[6] = %x\n", k,pOneCard->cardId[6]);
			//printf("pOneCard->cardId[7] = %x\n", k,pOneCard->cardId[7]);
			//printf("string:%s\n", pOneCard->cardId);
		}
		pOnePageInfo->useCards = useCards;
	}
	fclose(fpRead);
		
	pthread_rwlock_unlock(&(pCardInfos->lock));
	printAllCacheData();
}


static int getOnePageAccessCardInfo(const unsigned char pageNumber)
{
	static unsigned char sendBuf[1600];
	const unsigned char masterType = 0x20;
	const unsigned char slaveType = 0x00;
	const int PayloadLength = 5;
	const unsigned char ucMethod = 0x00;
		
	if(pageNumber >= MAX_PAGE_NUMBER)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "pageNum error ! pageNumber = %u\n", pageNumber);
		LOGD(logBuf);
		return -1; 
	}
		
	struct sockaddr_in aimServerAddr;
	unsigned int ipNum;
	unsigned short port;
	//int ret = creatIpNumAndPort(pgSystemParam->accessCardServerDomainName, ipNum, port, &(pgSystemParam->accessCardServerDomainNameLock));
	int ret = creatIpNumAndPort(defaultAccessCardServerDomainName, ipNum, port, &(pgSystemParam->accessCardServerDomainNameLock));
	if(ret < 0)
	{
    	char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "creatIpNumAndPort fail ! ret = %d\n", ret);
		LOGD(logBuf);
		return -2;
	}
    
	aimServerAddr.sin_family = AF_INET;
	aimServerAddr.sin_addr.s_addr = ipNum;
	aimServerAddr.sin_port = htons(port);
		
	int headLength = MakePackageHeadEx(sendBuf, masterType, slaveType, PayloadLength, ucMethod);
	memset(sendBuf + headLength, 0, 4);
	sendBuf[headLength + 4] = pageNumber;
		
	int packageSize = headLength + PayloadLength;
	MainSend(sendBuf, packageSize, &aimServerAddr);
	return 0;
}


int getOneAccessCardInfo(const char *pCardId,  const unsigned char cardIdBytes)
{
	static unsigned char sendBuf[1600];
	const unsigned char masterType = 0x20;
	const unsigned char slaveType = 0x01;
	int PayloadLength = 4 + 1 + cardIdBytes;
	const unsigned char ucMethod = 0x00;
		
	if(!pCardInfos)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "pCardInfos == NULL !\n");
		LOGD(logBuf);
		return -1;
	}

	if(!pOneCardProtoInfo)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "pOneCardProtoInfo == NULL !\n");
		LOGD(logBuf);
		return -2;
	}
		
	if(!pCardId || cardIdBytes >= MAX_CARD_NUMBER_BYTES)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "pCardId or cardIdBytes error ! cardIdBytes = %u MAX_CARD_NUMBER_BYTES=%u\n", cardIdBytes,MAX_CARD_NUMBER_BYTES);
		LOGD(logBuf);
		return -3;
	}
		
	struct sockaddr_in aimServerAddr;
	unsigned int ipNum;
	unsigned short port;
	//int ret = creatIpNumAndPort(pgSystemParam->accessCardServerDomainName, ipNum, port, &(pgSystemParam->accessCardServerDomainNameLock));
	int ret = creatIpNumAndPort(defaultAccessCardServerDomainName, ipNum, port, &(pgSystemParam->accessCardServerDomainNameLock));
	if(ret < 0)
	{
    	char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "creatIpNumAndPort fail ! ret = %d\n", ret);
		LOGD(logBuf);
		ret = getOneAccessCardInfoFromCache(pCardId, cardIdBytes);
		if (ret < 0)
		{
			return -4;
		}
		else
		{
			return 0;
		}
	}
	else
	{
		aimServerAddr.sin_family = AF_INET;
		aimServerAddr.sin_addr.s_addr = ipNum;
		aimServerAddr.sin_port = htons(port);

		int headLength = MakePackageHeadEx(sendBuf, masterType, slaveType, PayloadLength, ucMethod);
		memset(sendBuf + headLength, 0, 4);
		sendBuf[headLength + 4] = cardIdBytes;
		memcpy(&sendBuf[headLength + 4 + 1], pCardId, cardIdBytes);

		int packageSize = headLength + PayloadLength;
		MainSend(sendBuf, packageSize, &aimServerAddr);

		struct timespec ts;
		struct timeval  tv;
		while (1)
		{
			gettimeofday(&tv, NULL);
			ts.tv_sec = tv.tv_sec;
			ts.tv_nsec = tv.tv_usec * 1000;
			if (sem_timedwait(&(pOneCardProtoInfo->sem), &ts) != 0)
			{
				break;
			}
		}

		gettimeofday(&tv, NULL);
		ts.tv_sec = tv.tv_sec + getOneCardDataMaxWaitTime;
		ts.tv_nsec = tv.tv_usec * 1000;
		ret = sem_timedwait(&(pOneCardProtoInfo->sem), &ts);
		if (ret != 0)
		{
			char logBuf[logBufSize];
			snprintf(logBuf, logBufSize, "not recv proto return sem in %d second! ret = %d  try to get data form cache data !\n", getOneCardDataMaxWaitTime, ret);
			LOGD(logBuf);
			ret = getOneAccessCardInfoFromCache(pCardId, cardIdBytes);
			if (ret < 0)
			{
				return -5;
			}
			else
			{
				return 0;
			}
		}
	}

	unsigned char startTime[CARD_TIME_BYTES], stopTime[CARD_TIME_BYTES];
	LoopType loop;
	RealCardInfoType *pOne = &(pOneCardProtoInfo->realCardInfo);

	pthread_mutex_lock(&(pOneCardProtoInfo->lock));
	if (pOneCardProtoInfo->returnRet != 0)
	{
		LOGD_EX("recv proto data, telling cardid is not right !");
		pthread_mutex_unlock(&(pOneCardProtoInfo->lock));
		return -9;
	}

	if(pOne->cardIdBytes != cardIdBytes)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "pOne->cardIdBytes != cardIdBytes %u,%u\n", pOne->cardIdBytes, cardIdBytes);
		LOGD(logBuf);
		pthread_mutex_unlock(&(pOneCardProtoInfo->lock));
		return -6;
	}
    
	unsigned char i;
	for(i = 0; i < cardIdBytes; i ++)
	{
		if (pOne->cardId[i] != pCardId[i])
		{
			char logBuf[logBufSize];
			snprintf(logBuf, logBufSize, "pOne->cardId[%u] != pCardId[%u] %u,%u\n", i, i, pOne->cardId[i], pCardId[i]);
			LOGD(logBuf);
			pthread_mutex_unlock(&(pOneCardProtoInfo->lock));
			return -7;
		}
	}
    
	memcpy(startTime, pOne->startTime, CARD_TIME_BYTES);
	memcpy(stopTime, pOne->stopTime, CARD_TIME_BYTES);
	loop = pOne->loop;
	if(loop >= eMaxLoop)
	{
    	char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "loop >= eMaxLoop %u,%u\n", i, i, loop, eMaxLoop);
		LOGD(logBuf);
		pthread_mutex_unlock(&(pOneCardProtoInfo->lock));
		return -8;
	}
	pthread_mutex_unlock(&(pOneCardProtoInfo->lock));
    
	printf("package return time data:\n");
	printf("start:");
	for(i = 0; i < CARD_TIME_BYTES; i ++)
	{
		printf("%u ", startTime[i]);
	}
	printf("\n");

	printf("stop:");
	for (i = 0; i < CARD_TIME_BYTES; i++)
	{
		printf("%u ", stopTime[i]);
	}
	printf("\n");

	ret = checkTimeOk(startTime, stopTime, loop);
	return ret;
}


static int checkTimeOk(const unsigned char *pStart, const unsigned char *pStop, const LoopType loop)
{
	/*printf("org start time:");
	for(unsigned char ii; ii < CARD_TIME_BYTES; ii ++)
	{
			printf("%x ", pStart[ii]);	
	}
	printf("\n");
		
	printf("org stop time:");
	for(unsigned char ii; ii < CARD_TIME_BYTES; ii ++)
	{
			printf("%x ", pStop[ii]);	
	}
	printf("\n");*/
		
	struct tm start = changeDateInfoFromArrayToStruct(pStart);
	struct tm stop = changeDateInfoFromArrayToStruct(pStop);
	if(start.tm_mon > 11 || start.tm_mday > 31 || stop.tm_mon > 11 || stop.tm_mday > 31)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "start or stop time error ! %d,%d, %d,%d\n", start.tm_mon, start.tm_mday, stop.tm_mon, stop.tm_mday);
		LOGD(logBuf);
		return -1;
	}
		
	int ret = checkTimeEqual(&start, &stop);
	if(ret >= 0)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "checkTimeEqual >= 0! ret=%d\n", ret);
		LOGD(logBuf);
		return -2;
	}
		
	time_t nowTime;
	time(&nowTime);	
	struct tm *pTime = localtime(&nowTime);	
		
	printf("wait check time data list:\n");
	printf("now:%d,%d,%d,%d,%d,%d,%d\n",pTime->tm_year,pTime->tm_mon,pTime->tm_mday,pTime->tm_wday,pTime->tm_hour,pTime->tm_min,pTime->tm_sec);
	printf("start:%d,%d,%d,%d,%d,%d,%d\n",start.tm_year,start.tm_mon,start.tm_mday,start.tm_wday,start.tm_hour,start.tm_min,start.tm_sec);
	printf("stop:%d,%d,%d,%d,%d,%d,%d\n",stop.tm_year,stop.tm_mon,stop.tm_mday,stop.tm_wday,stop.tm_hour,stop.tm_min,stop.tm_sec);
		
	int ret1 = checkTimeEqual(pTime, &start, loop);
	int ret2 = checkTimeEqual(pTime, &stop, loop);
	if(ret1 >= 0 && ret2 <= 0) ret = 0;
	else ret = -1;
		
	char logBuff[logBufSize];
	snprintf(logBuff, logBufSize, "ret,ret1,ret2=%d,%d,%d\n", ret,ret1,ret2);
	LOGD(logBuff);
	return ret;
}

static int checkTimeEqual(const struct tm *tA, const struct tm *tB, LoopType loop)
{
	int ret;
	switch (loop)
	{
	case eNotLoop:
		ret = checkTimeEqualNotLoop(tA, tB);
		break;
	case eDayLoop:
		ret = checkTimeEqualDayLoop(tA, tB);
		break;
	case eWeekLoop:
		ret = checkTimeEqualWeekLoop(tA, tB);
		break;
	case eMonthLoop:
		ret = checkTimeEqualMonthLoop(tA, tB);
		break;
	default:
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "unknow loop value %u, set ret = 0!\n", loop);
		LOGD(logBuf);
		ret = 0;
		break;
	}

		return ret;
}

static int checkTimeEqualNotLoop(const struct tm *tA, const struct tm *tB)
{
	if (tA->tm_year > tB->tm_year) return 1;
	else if (tA->tm_year < tB->tm_year) return -1;

	if (tA->tm_mon > tB->tm_mon) return 2;
	else if (tA->tm_mon < tB->tm_mon) return -2;

	if (tA->tm_mday > tB->tm_mday) return 3;
	else if (tA->tm_mday < tB->tm_mday) return -3;

	if (tA->tm_hour > tB->tm_hour) return 4;
	else if (tA->tm_hour < tB->tm_hour) return -4;

	if (tA->tm_hour > tB->tm_min) return 5;
	else if (tA->tm_hour < tB->tm_min) return -5;

	if (tA->tm_hour > tB->tm_sec) return 6;
	else if (tA->tm_hour < tB->tm_sec) return -6;

	return 0;
}

static int checkTimeEqualDayLoop(const struct tm *tA, const struct tm *tB)
{	
	if(tA->tm_hour > tB->tm_hour) return 4;
	else if(tA->tm_hour < tB->tm_hour) return -4;
			
	if(tA->tm_hour > tB->tm_min) return 5;
	else if(tA->tm_hour < tB->tm_min) return -5;
			
	if(tA->tm_hour > tB->tm_sec) return 6;
	else if(tA->tm_hour < tB->tm_sec) return -6;
			
	return 0;	
}

static int checkTimeEqualMonthLoop(const struct tm *tA, const struct tm *tB)
{
	if(tA->tm_mday > tB->tm_mday) return 3;
	else if(tA->tm_mday < tB->tm_mday) return -3;
		
	if(tA->tm_hour > tB->tm_hour) return 4;
	else if(tA->tm_hour < tB->tm_hour) return -4;
			
	if(tA->tm_hour > tB->tm_min) return 5;
	else if(tA->tm_hour < tB->tm_min) return -5;
			
	if(tA->tm_hour > tB->tm_sec) return 6;
	else if(tA->tm_hour < tB->tm_sec) return -6;
			
	return 0;	
}

static int checkTimeEqualWeekLoop(const struct tm *tA, const struct tm *tB)
{
	if(tA->tm_wday > tB->tm_wday) return 3;
	else if(tA->tm_mday < tB->tm_wday) return -3;
		
	if(tA->tm_hour > tB->tm_hour) return 4;
	else if(tA->tm_hour < tB->tm_hour) return -4;
			
	if(tA->tm_hour > tB->tm_min) return 5;
	else if(tA->tm_hour < tB->tm_min) return -5;
			
	if(tA->tm_hour > tB->tm_sec) return 6;
	else if(tA->tm_hour < tB->tm_sec) return -6;
		
	return 0;	
}

static struct tm changeDateInfoFromArrayToStruct(const unsigned char *pTime)
{
	struct tm t;
	t.tm_year = pTime[0] + 100;
	t.tm_mon  = pTime[1] - 1;
	t.tm_mday = pTime[2];
	t.tm_hour = pTime[3];
	t.tm_min  = pTime[4];
	t.tm_sec  = pTime[5];
		
	t.tm_wday = getWday(t.tm_year + 1900, t.tm_mon, t.tm_mday);
		
	return t;
}

static unsigned char getWday(const int year, const int month, const int mday)
{
	if (year <= 1582 || month < 0 || month > 11 || mday < 1 || mday > 31)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "getWday param error ! %d,%d,%d\n", year, month, mday);
		LOGD(logBuf);
	}

	int c, y, m, d, cyTmp, mTmp, dTmp, w;
	if (month + 1 < 3)
	{
		cyTmp = year - 1;
		mTmp = month + 12 + 1;
	}
	else
	{
		cyTmp = year;
		mTmp = month + 1;
	}
	dTmp = mday;

	c = (cyTmp / 100) & 0x000000FF;
	y = cyTmp % 100;
	m = mTmp;
	d = dTmp;
	printf("getWday:%d,%d,%d,%d\n", c, y, m, d);
	w = (y + y / 4 + c / 4 - 2 * c + 26 * (m + 1) / 10 + d - 1) % 7;
	return w;
}


static void* dataPersistenceThread(void *arg)
{
	loadPersistenceData();
	sleep(delayBeforeFisrtTimeToGetAllData);

	int ret;
	while (!IsExit())
	{
		ret = getAllAccessCardInfo();
		if (ret == 0)
		{
			dataPersistence();
			sleep(persistenceTimeInteral_S);
		}
		else
		{
			sleep(retryDelayTimeWhenGetAllDataFail_S);
		}
	}
}


static int getOneAccessCardInfoFromCache(const char *pCardId,  const unsigned char cardIdBytes)
{
	int ret;
	unsigned char i,j,k;
	unsigned char *a, *b, l;
	char lineData[MAX_BYTES_IN_LINE];
	PageCardInfoType *pPageInfos = pCardInfos->realCardInfos;
	PageCardInfoType *pOnePageInfo;
	RealCardInfoType *pOnePageCardIds;
	RealCardInfoType *pOneCard;
		
	pthread_rwlock_rdlock(&(pCardInfos->lock));
	if(cardIdBytes != pCardInfos->bytesOfEachCard)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "getOneAccessCardInfoFromCache fail because byteSize not match ! %u,%u\n", cardIdBytes, pCardInfos->bytesOfEachCard);
		LOGD(logBuf);
		printf("card id = ");
		for (i = 0; i < cardIdBytes; i++)
		{
			printf("%x ", pCardId[i]);
		}
		printf("\n");
		pthread_rwlock_unlock(&(pCardInfos->lock));
		return -1;
	}
		
	pOneCard = &pOnePageCardIds[j];
	printf("wait check card:");
	for(k = 0; k < cardIdBytes; k ++)
	{
		printf("%x ", pCardId[k]);	
	}
	printf("\n");
						
	for(i = 0; i < pCardInfos->totalPageNum; i ++)
	{
		pOnePageInfo = &pPageInfos[i];
		pOnePageCardIds = pOnePageInfo->realCardInfo;
		for (j = 0; j < pOnePageInfo->useCards; j++)
		{
			pOneCard = &pOnePageCardIds[j];
			printf("%u,%u:", i, j);
			for (k = 0; k < cardIdBytes; k++)
			{
				printf("%x ", pOneCard->cardId[k]);
			}
			printf("\n");
			ret = strcmpEx(pOneCard->cardId, pCardId, cardIdBytes);
			if (ret < 0) continue;

			printf("cardId match ! prepare to check time !\n");
			ret = checkTimeOk(pOneCard->startTime, pOneCard->stopTime, pOneCard->loop);
			if (ret < 0) ret = -2;
			else ret = 0;
			pthread_rwlock_unlock(&(pCardInfos->lock));
			return ret;
		}
	}
		
	char logBuf[logBufSize];
	snprintf(logBuf, logBufSize, "getOneAccessCardInfoFromCache fail because no cardid can match !\n");
	LOGD(logBuf);
	pthread_rwlock_unlock(&(pCardInfos->lock));
	return -3;
}

static int strcmpEx(const char *strA, const char *strB, const unsigned char size)
{
	unsigned char i;
	for (i = 0; i < size; i++)
	{
		if (strA[i] != strB[i]) return -1;
	}

	return 0;
}

static void changeTimeFormat(unsigned char *pOut, const char *pIn)
{
	if (!pOut || !pIn) return;

	unsigned char i;
	unsigned char low, high;
	for (i = 0; i < CARD_TIME_BYTES; i++)
	{
		high = pIn[i * 2] - '0';
		low = pIn[i * 2 + 1] - '0';
		pOut[i] = high * 10 + low;
		printf("high=%u,low=%u,out[%u]=%u\n", high, low, i, pOut[i]);
	}
}

static void reverseChangeTimeFormat(char *pOut, const unsigned char *pIn)
{
	if (!pOut || !pIn) return;

	printf("reverseChangeTimeFormat:pIn=");
	unsigned char i;
	unsigned char low, high;
	for (i = 0; i < CARD_TIME_BYTES; i++)
	{
		low = pIn[i] % 10;
		high = pIn[i] / 10;
		pOut[i * 2] = high + '0';
		pOut[i * 2 + 1] = low + '0';
		printf("%u", pIn[i]);
	}
	pOut[CARD_TIME_BYTES * 2] = '\0';
	printf("\n");
}



static void printAllCacheData()
{
	if (!pCardInfos) return;

	unsigned char i, j, k;
	PageCardInfoType *pPageInfos = pCardInfos->realCardInfos;
	PageCardInfoType *pOnePageInfo;
	RealCardInfoType *pOnePageCardIds;
	RealCardInfoType *pOneCard;
	pthread_rwlock_rdlock(&(pCardInfos->lock));
	printf("!!!! printAllCacheData:%u,%u\n", pCardInfos->totalPageNum, pCardInfos->bytesOfEachCard);
	for (i = 0; i < pCardInfos->totalPageNum; i++)
	{
		pOnePageInfo = &pPageInfos[i];
		pOnePageCardIds = pOnePageInfo->realCardInfo;
		for (j = 0; j < pOnePageInfo->useCards; j++)
		{
			pOneCard = &pOnePageCardIds[j];
			printf("%u,%u,string:%s\n", i, j, pOneCard->cardId);
			for (k = 0; k < pCardInfos->bytesOfEachCard; k++)
			{
				printf("%u,%u,bin:%x\n", i, j, pOneCard->cardId[k]);
			}
			printf("start time:");
			for (k = 0; k < CARD_TIME_BYTES; k++)
			{
				printf("%x ", pOneCard->startTime[k]);
			}
			printf("\n");
			printf("stop time:");
			for (k = 0; k < CARD_TIME_BYTES; k++)
			{
				printf("%x ", pOneCard->stopTime[k]);
			}
			printf("\n");
			printf("loop = %u\n", (unsigned char)pOneCard->loop);
		}
	}
	pthread_rwlock_unlock(&(pCardInfos->lock));
}
